#coding:utf-8

import serial

import socket
import time
import sys
import threading
import os


def query_local_ip():
    st = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:       
        st.connect(('8.8.8.8', 80))
        IP = st.getsockname()[0]
    except Exception:
        IP = '0.0.0.0'
    finally:
        st.close()
    return IP



class SerialDecoder(object):

    def __init__(self, bufsize=200, com='/dev/ttyAMA0', band=9600, debug=True):
        self.ser = serial.Serial(com, band)



class UartRx2ClentThread(threading.Thread):
    '''
        功能为读取串口接收到的数据(按行读取 有阻塞性)并转发给远程客户端
    '''
    def __init__(self, daemon=None,sock=None,uart=None):
        super(UartRx2ClentThread, self).__init__(daemon=daemon)
        self.__is_running = True
        self.daemon = daemon
        self.sock = sock
        self.uart = uart 
    def terminate(self):
        self.__is_running = False
 
    def run(self):
        pid = os.getpid()
        if self.uart.isOpen() == False:
            self.uart.open()
        while(self.__is_running):
            try:
                msg = self.uart.readline()  #读取的数据包含了换行符
                print('接收到串口数据: '+ msg.decode('gb2312') , end='')
                self.sock.send(msg)
        
            except Exception as err:
                print('XXX 接收串口线程 异常')
                print(err)
            
        if self.uart.isOpen() == True:
            self.uart.close()



# #####################################################################
#             下面开始才是正式执行语句
# #####################################################################
if(2 != len(sys.argv)):
    print("参数个数不对!")
    print("Usage: python "+sys.argv[0]+"  <本机串口设备名>")
    sys.exit(1)
    
host_ip = '0.0.0.0'   #query_local_ip()
port = 10086

host_addr = (host_ip,port)

socket_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_tcp.bind(host_addr)
socket_tcp.listen(1)


def main_func(dev_name):
    ''' 主线程调用此函数完成的事情：
        1）接收远程客户端的连接
        2）接收远程客户端发送的指令数据并转发给下面的串口设备
        3）创建子线程处理串口反馈的数据给客户端
        4）管理客户端会话，保持永久在线
    '''
    while True:
        print("监听端口 10086 等待连接...")
        conn,(client_ip, client_port) = socket_tcp.accept()
        print("Connection accepted from %s." %client_ip)
        
        sd1 = SerialDecoder(500, dev_name, 256000, True)
        
        thread1 = UartRx2ClentThread(True,conn,sd1.ser) #创建子线程进行接收串口数据并转发给客户端的操作
        thread1.start()
        
        print("等待远程client端输入...")
        while True:     
            try:
                recv_data = conn.recv(256) 
                print("客户端输入是: " + recv_data.decode())
                if(recv_data[len(recv_data)-1] == 0x09):
                    sd1.ser.write(recv_data)
                else:
                    sd1.ser.write(recv_data + b'\n')  #下发给单片机Shell进程时最后要加个换行符
        
            except Exception:
                print('Connection  interrupt!')
                thread1.terminate()  #客户端会话中止，结束子线程
                sd1.ser.close()
                time.sleep(0.2)
                print('重新等待新客户端连接~~~')
                break

    
        
main_func(sys.argv[1])
